package com.orcamento.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractDao<T> {
	
	@Autowired
	private SessionFactory sessionFactory;
	private Class<? extends Object> clazz;

	protected AbstractDao(Class<? extends Object> clazz) {
		this.clazz = clazz;
	}
	
	protected Session session() {
		return sessionFactory.getCurrentSession();
	}
	
	protected T saveEntity(T entity) {
		session().saveOrUpdate(entity);
		return entity;
	}
	
	@SuppressWarnings("unchecked")
	protected List<T> findAllByAccount( Long accountId ) {
		Criteria criteria = session().createCriteria( clazz );
		criteria.createAlias("account", "account", JoinType.INNER_JOIN);
		criteria.add( Restrictions.eq("account.id", accountId) );
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	protected List<T> findAllByAccount(Long accountId, Order orderBy) {
		Criteria criteria = session().createCriteria( clazz );
		criteria.createAlias("account", "account", JoinType.INNER_JOIN);
		criteria.add( Restrictions.eq("account.id", accountId) );
		criteria.addOrder(orderBy);
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	protected T findById(long primaryKey) {
		return (T) session().get(clazz, primaryKey);
	}
	
	@SuppressWarnings("unchecked")
	protected T findByIdAndAccount(Long id, Long accountId) {
		Criteria criteria = session().createCriteria(clazz);
		criteria.createAlias("account", "account", JoinType.INNER_JOIN);
		criteria.add(Restrictions.eq("id", id));
		criteria.add(Restrictions.eq("account.id", accountId));
		return (T) criteria.uniqueResult();
	}
	
	protected void delete(T entity) {
		session().delete( session().merge(entity) );
	}
	
	@SuppressWarnings("unchecked")
	protected List<T> findBetweenByAccount(String field, Object lowerObject, Object highestObject, Long accountId) {
		return session().createCriteria(clazz).
				createAlias("account", "account", JoinType.INNER_JOIN).
				add( Restrictions.ge( field, lowerObject) ).
				add( Restrictions.le( field, highestObject) ).
				add( Restrictions.eq("account.id", accountId) ).
				list();
	}
	
}
